package com.tengju.data.application.profit;

import com.tengju.data.domain.model.alert.AlertEvent;
import com.tengju.data.domain.model.alert.AlertService;
import com.tengju.data.domain.model.report.*;
import com.tengju.data.domain.model.service.AchievementBonusDateConfigService;
import com.tengju.data.domain.model.service.DataVersionService;
import com.tengju.data.domain.model.service.MarketBonusCalService;
import com.tengju.data.domain.model.service.UserStarService;
import com.tengju.data.domain.model.user.UserIdCode;
import com.tengju.data.domain.model.user.UserStarFeature;
import com.tengju.data.domain.model.user.UserStarFeatureSnapshotRepository;
import com.tengju.data.domain.shared.CastUtil;
import com.tengju.data.domain.shared.DateUtil;
import com.tengju.data.domain.shared.JsonUtil;
import com.tengju.data.domain.shared.tree.Forest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;

@Service
@Slf4j
@RequiredArgsConstructor(onConstructor_ = {@Autowired})
public class MarketBonusService {

    private final AchievementBonusRepository marketProfitRepository;
    private final MarketBonusCalService marketBonusCalService;
    private final UserStarService userStarExternalService;
    private final UserStarFeatureSnapshotRepository userStarFeatureSnapshotRepository;
    private final DataVersionService dataVersionService;
    private final AchievementBonusRiskRepository achievementBonusRiskRepository;
    private final AchievementBonusCalMidInfoRepository midInfoRepository;
    private final AchievementBonusDateConfigService configService;
    private final AlertService alertService;

    public boolean calRealtimeMarketBonus() {
        LocalDateTime logTime = LocalDateTime.now().withNano(0);
        Integer month = DateUtil.formatMonthInt(logTime);

        //根据配置表查询数据周期，查不到数据默认自然月
        AchievementBonusDateConfig dateConfig = configService.queryByCalDateOrDefault(logTime.toLocalDate());
        if (dateConfig != null) {
            month = CastUtil.castInt(dateConfig.getDataKey());
        }

        int maxVersion = marketProfitRepository.getMaxVersion();
        log.info("小时市场补贴开始计算，month:{},logtime:{}", month, logTime.toString());

        log.info("小时市场补贴>>生成中间记录表，month:{},logtime:{}", month, logTime.toString());
        midInfoRepository.saveMarketProfitMidInfoRealtime(month, logTime);

        log.info("小时市场补贴>>小团队关系树生成，month:{},logtime:{}", month, logTime.toString());
        Forest<MarketReport> marketReportForest = marketBonusCalService.initMarketReport(logTime, month, AchievementBonusCalTypeEnum.REALTIME);
        if (marketReportForest == null) {
            log.info("还没有当月数据，month:{}, logtime:{}", month, logTime.toString());
            return true;
        }

        log.info("小时市场补贴>>计算市场补贴，month:{},logtime:{}", month, logTime.toString());
        marketBonusCalService.calMarketBonus(marketReportForest);

        marketBonusCalService.saveAchievementBonus(marketReportForest,maxVersion + 1);
        marketProfitRepository.deleteInvalidData(month,maxVersion + 1);

        log.info("小时市场补贴>>市场补贴结果存储快照日志，month:{},logtime:{}", month, logTime.toString());
        marketProfitRepository.saveAchievementBonusLog(logTime, month);

        log.info("月市场补贴>>计算完成!，month:{},logtime:{}", month, logTime.toString());

        return true;
    }

    public boolean calMonthMarketBonus(Integer month) {
        LocalDateTime logTime = LocalDateTime.now().withNano(0);

        month = getCalMonth(logTime,month);
        if (month == null) {
            return false;
        }

        log.info("月市场补贴开始计算，month:{},logtime:{}", month, logTime.toString());
        int maxVersion = marketProfitRepository.getMaxVersion();
        if (!checkMonthData(month)) {
            throw new AchievementBonusCalException("月市场补贴任务，上游数据未准备好!,month:" + month);
        }

        log.info("月市场补贴>>生成中间记录表，month:{},logtime:{}", month, logTime.toString());
        midInfoRepository.saveMarketProfitMidInfoMonthSnapshot(logTime, month);

        log.info("月市场补贴>>小团队关系树生成，month:{},logtime:{}", month, logTime.toString());
        Forest<MarketReport> marketReportForest = marketBonusCalService.initMarketReport(logTime, month, AchievementBonusCalTypeEnum.MONTH);
        if (marketReportForest == null) {
            log.info("还没有当月数据，month:{},logtime:{}", month, logTime.toString());
            return true;
        }

        log.info("月市场补贴>>计算市场补贴，month:{},logtime:{}", month, logTime.toString());
        marketBonusCalService.calMarketBonus(marketReportForest);

        marketBonusCalService.saveAchievementBonus(marketReportForest, maxVersion + 1);

        marketProfitRepository.deleteInvalidData(month,maxVersion + 1);

        log.info("月市场补贴>>市场补贴结果存储快照日志，month:{},logtime:{}", month, logTime.toString());
        marketProfitRepository.saveAchievementBonusLog(logTime, month);

        log.info("月市场补贴>>计算完成!，month:{},logtime:{}", month, logTime.toString());

        AlertEvent event = new AlertEvent("月市场补贴已完成," + month);
        alertService.alert(event);
        return true;
    }

    private Integer getCalMonth(LocalDateTime now, Integer month) {
        LocalDate today = now.toLocalDate();
        //手动输入的月份直接执行
        if (month != null) {
            return month;
        }
        //根据配置表查询当天是否月度计算日期，如果否直接退出
        AchievementBonusDateConfig dateConfig = configService.queryByLastCalDate(now.toLocalDate());
        if (dateConfig == null) {
            log.info("月市场补贴计算，{}, 不是月度计算日期。", today);
            return null;
        }
        if (!dateConfig.canLastCal(today)) {
            log.info("月市场补贴计算, {}, 月度计算日期不合法,config:{}", today, JsonUtil.toJSONString(dateConfig));
            throw new AchievementBonusCalException(String.format("月市场补贴计算, %s, 月度计算日期不合法", today));
        }
        return CastUtil.castInt(dateConfig.getDataKey());
    }

    /**
     * 风控业绩奖励对比计算
     * @param month 月度
     * @return 结果
     */
    public boolean calMonthMarketBonusRisk(Integer month) {
        LocalDateTime logTime = LocalDateTime.now().withNano(0);

        month = getCalRiskMonth(logTime,month);
        if (month == null) {
            return false;
        }

        log.info("风控业绩奖励对比 - 月市场补贴开始计算，month:{},logtime:{}", month, logTime.toString());
        int maxVersion = achievementBonusRiskRepository.getMaxVersion();
        if (!checkRiskMonthData(month)) {
            throw new AchievementBonusCalException("风控业绩奖励对比 - 月市场补贴任务，上游数据未准备好!,month:" + month);
        }

        log.info("风控业绩奖励对比 - 月市场补贴>>生成中间记录表，month:{},logtime:{}", month, logTime.toString());
        midInfoRepository.saveMarketProfitMidInfoMonthRisk(logTime, month);

        log.info("风控业绩奖励对比 - 月市场补贴>>小团队关系树生成，month:{},logtime:{}", month, logTime.toString());
        Forest<MarketReport> marketReportForest = marketBonusCalService.initMarketReport(logTime, month, AchievementBonusCalTypeEnum.MONTH_RISK);
        if (marketReportForest == null) {
            log.info("还没有当月数据，month:{},logtime:{}", month, logTime.toString());
            return true;
        }

        log.info("风控业绩奖励对比 - 月市场补贴>>计算市场补贴，month:{},logtime:{}", month, logTime.toString());
        marketBonusCalService.calMarketBonus(marketReportForest);

        marketBonusCalService.saveAchievementBonusRisk(marketReportForest, maxVersion + 1);
        achievementBonusRiskRepository.deleteInvalidData(month,maxVersion + 1);

        log.info("风控业绩奖励对比 - 月市场补贴>>计算完成!，month:{},logtime:{}", month, logTime.toString());

        AlertEvent event = new AlertEvent("风控业绩奖励对比完成," + month);
        alertService.alert(event);

        return true;
    }

    private Integer getCalRiskMonth(LocalDateTime now, Integer month) {
        LocalDate today = now.toLocalDate();
        //手动输入的月份直接执行
        if (month != null) {
            return month;
        }
        //根据配置表查询当天是否月度风控计算日期，如果否直接退出
        AchievementBonusDateConfig dateConfig = configService.queryByRiskDate(today);
        if (dateConfig == null) {
            log.info("风控业绩奖励对比，{}, 不是计算日期。", today);
            return null;
        }
        if (!dateConfig.canCalRisk(today)) {
            log.info("风控业绩奖励对比, {}, 计算日期不合法,config:{}", today, JsonUtil.toJSONString(dateConfig));
            throw new AchievementBonusCalException(String.format("月市场补贴计算, %s, 月度计算日期不合法", today));
        }
        return CastUtil.castInt(dateConfig.getDataKey());
    }

    /**
     * 风控业绩奖励对比 - 上游数据准备校验
     * @param month 月度
     * @return 结果
     */
    private boolean checkRiskMonthData(Integer month) {
        return dataVersionService.checkAchievementRiskVersion(month) &&
                dataVersionService.checkRelationVersion(month) &&
                dataVersionService.checkStarVersion(month);
    }

    public void saveStarMonthSnapshot(Integer month) {
        LocalDate ytd = LocalDate.now().minusDays(1);
        if (month == null) {
            AchievementBonusDateConfig dateConfig = configService.queryByCalDateOrDefault(ytd);
            if (dateConfig == null || !dateConfig.isPeriodEndDate(ytd)) {
                log.info("月星级快照，{}, 不是计算日期。", LocalDate.now());
                return;
            }
            month = CastUtil.castInt(dateConfig.getDataKey());
        }

        List<UserStarFeature> userStarFeatures = userStarExternalService.listStarFeature();
        userStarFeatureSnapshotRepository.saveStarFeatureMonthSnapshot(month, userStarFeatures);
        dataVersionService.saveVersion(DataNameEnum.USER_STAR,month);

        AlertEvent event = new AlertEvent("月星级快照任务," + month);
        alertService.alert(event);
    }

    private boolean checkMonthData(Integer month) {
        return dataVersionService.checkAchievementVersion(month) &&
                dataVersionService.checkRelationVersion(month) &&
                dataVersionService.checkStarVersion(month);
    }

    public BigDecimal calculateAdvertIndex(LocalDate month, UserIdCode idCode) {
        List<AchievementBonus> achievementBonuses = marketProfitRepository.find(month, idCode);
        BigDecimal totalAdvertIndex = new BigDecimal("0");
        for (AchievementBonus achievementBonus : achievementBonuses) {
            totalAdvertIndex = totalAdvertIndex.add(achievementBonus.getProfit());
        }
        return totalAdvertIndex;
    }

    public BigDecimal calculateAdvertIndexByConfig(Integer dateKey, UserIdCode idCode) {
        List<AchievementBonus> achievementBonuses = marketProfitRepository.findByConfigDateKey(dateKey,idCode);
        BigDecimal totalAdvertIndex = BigDecimal.ZERO;
        for (AchievementBonus achievementBonus : achievementBonuses) {
            totalAdvertIndex = totalAdvertIndex.add(achievementBonus.getProfit());
        }
        return totalAdvertIndex;
    }

    public void clearMarketProfitMidTable(LocalDateTime clearDate) {
        log.info("清除{}之前的历史记录",clearDate);
        List<LocalDateTime> logTimes = midInfoRepository.listLogtimeBeforeClearDate(clearDate);
        if (CollectionUtils.isEmpty(logTimes)) {
            return;
        }
        for (LocalDateTime logTime : logTimes) {
            log.info("清除 logtime:{} 历史数据",logTime);
            midInfoRepository.clearHistoryRecord(logTime);
        }
    }



}
